;Frequency display and VFO stabiliser (c)1993 - 2000 E.Skelton.
;Crystal freq. 4.000MHz
;I.F. offsets.  7.99850 and 8.00150 for an I.F. of 8.0 MHz
;Conversion to the 8.0 MHz If done by W6JFR

		List P=16F84, F=INHX8M
		#Include <P16F84.Inc>
		__CONFIG  0X3Ff9
	
        

HI_ERR	EQU	0x05		
LOK_FLG	EQU	0x06
CARRY	EQU	0x00
STATUS	EQU	0x03
Z	EQU	0x02
RA      EQU     0x05
RB      EQU     0x06
RTCC    EQU     0x01
PC      EQU     0x02
FSR     EQU     0x04

W	EQU	0x00
F	EQU	0x01

PS0	EQU	0x00
PS1	EQU	0x01
PS2	EQU	0x02
PSA	EQU	0x03
RTE	EQU	0x04
RTS	EQU	0x05
INTEDG	EQU	0x06
RBPU	EQU	0x07


;********* USER DEF'S **********

GATE    EQU     0x03	;COUNTER GATE
UP_CNT	EQU	0x02    ;CLOCK UP 1 (ALSO ACTS AS SECOND GATE)
RESET   EQU     0x01	;COUNTER RESET
HUFF	EQU	0x01
PUFF	EQU	0x00
RS	EQU	0x03
ENA	EQU	0x02
UP_DWN	EQU	0x04
SBS	EQU	0x05
BUTTON	EQU	0x06
UDC	EQU	0x10
LST_DIG	EQU	0x11
ERR_LEV	EQU	0x12
L	EQU	0x13
M	EQU	0x14
H	EQU	0x15
COUNT	EQU	0x16
TEMP	EQU	0x17
COUNT1  EQU     0x18
COUNT2  EQU     0x19
COUNT3  EQU     0x1A
COUNT4	EQU	0x1B
CHR	EQU	0x1C
CNT1_L	EQU	0x1D
CNT1_M	EQU	0x1E
CNT1_H	EQU	0x1F
H_BYTE	EQU	0x20
M_BYTE	EQU	0x21
L_BYTE	EQU	0x23
R0	EQU	0x24
R1	EQU	0x25
R2	EQU	0x26
R3	EQU	0x27
COUNT5	EQU	0x28
FLAGS	EQU	0x29


	ORG	0x00
	GOTO	START


;******** DELAY LOOP ********
;** WATCH OUT FOR CALL TO MS100

DECI	MOVWF	COUNT4		;DELAY 100MS X CONTENTS (W)
NXT6	CALL	MS100
	DECFSZ	COUNT4,1
	GOTO	NXT6
	RETLW	0
;*****************************



;******** DELAY LOOP 100MS ***********
MS100	MOVLW	0x2D			;100 MS DELAY LOOP		
	MOVWF	COUNT1                  ;EXACT TIMING .1 SEC
L1	MOVLW	0x0C                    ;INCLUDING CALL AND RETURN
	MOVWF	COUNT2                  ;4 MHZ XTAL
L2	MOVLW	0X3C
	MOVWF	COUNT3                  
L3	DECFSZ	COUNT3,1
	GOTO	L3
	DECFSZ	COUNT2,1
	GOTO	L2
	DECFSZ	COUNT1,1
	GOTO	L1
	MOVLW	0x96
	MOVWF	COUNT1
LP99	DECFSZ	COUNT1,1
	GOTO	LP99
	NOP
	NOP
        RETLW	0
;****************************************




;******** DELAY LOOP 200 MICRO SEC. *************
DELAY	MOVLW   0x42 		;DELAY LOOP 200 MICROSEC
        MOVWF   COUNT1     
NXT5    DECFSZ  COUNT1,1
        GOTO    NXT5    
        RETLW   0
;*************************************************





;*********** DELAY LOOP 2MS ***********************
MS2	MOVLW	0x0A 		;DELAY 2MS
	MOVWF	COUNT1
LP15	MOVLW	0x42
	MOVWF	COUNT2
LP16	DECFSZ	COUNT2,1
	GOTO	LP16
	DECFSZ	COUNT1,1
	GOTO	LP15
	RETLW	0           
;**************************************************






;******* CONVERT 24 BIT BIN TO PACKED BCD **********

B2_BCD	BCF	STATUS,CARRY
	MOVLW	0x18
	MOVWF	COUNT
	CLRF	R0
	CLRF	R1
	CLRF	R2
	CLRF	R3
LOOP16	RLF	L_BYTE,F
	RLF	M_BYTE,F
	RLF	H_BYTE,F
	RLF	R0,F
	RLF	R1,F
	RLF	R2,F
	RLF	R3,F

	DECFSZ	COUNT,1
	GOTO	ADJDEC
	RETLW	0 

ADJDEC	MOVLW	R3
	MOVWF	FSR 
	CALL	ADJBCD


	MOVLW	R2
	MOVWF	FSR 
	CALL	ADJBCD

	MOVLW	R1
	MOVWF	FSR
	CALL	ADJBCD

	MOVLW	R0
	MOVWF	FSR
	CALL	ADJBCD

	GOTO	LOOP16

ADJBCD	MOVLW	0x03
	ADDWF	0,W
	MOVWF	TEMP
	BTFSC	TEMP,3
	MOVWF	0
	MOVLW	0x30
	ADDWF	0,W
	MOVWF	TEMP
	BTFSC	TEMP,7
	MOVWF	0
	RETLW	0	

;****************************************





;*********** INITIALISE LCD MODULE 4 BIT MODE ***********************
LCDINIT	CALL	MS100		;WAIT FOR LCD MODULE HARDWARE RESET
	BCF	RA,RS		;REGISTER SELECT LOW
	BCF	RA,ENA		;ENABLE LINE LOW
	
	MOVLW	0x03
	MOVWF	RB		;8 BIT MODE
	BSF	RA,ENA          ;ENA HIGH
	NOP                     ;MORE THAN 470 NS
	BCF	RA,ENA		;ENA	LOW
	CALL	MS100       	;WAIT FOR DISPLAY TO CATCH UP


	MOVLW	0x03
	MOVWF	RB		;8 BIT MODE
	BSF	RA,ENA          ;ENA HIGH
	NOP                     ;MORE THAN 470 NS
	BCF	RA,ENA		;ENA	LOW
	CALL	DELAY       	;WAIT FOR DISPLAY TO CATCH UP

	MOVLW	0x03
	MOVWF	RB		;8 BIT MODE
	BSF	RA,ENA          ;ENA HIGH
	NOP                     ;MORE THAN 470 NS
	BCF	RA,ENA		;ENA	LOW
	CALL	DELAY       	;WAIT FOR DISPLAY TO CATCH UP


	MOVLW	0x02
	MOVWF	RB		;4 BIT MODE
	BSF	RA,ENA          ;ENA HIGH
	NOP                     ;MORE THAN 470 NS
	BCF	RA,ENA		;ENA	LOW
	CALL	DELAY       	;WAIT FOR DISPLAY

	MOVLW	0x0C		;DISPLAY ON
	CALL	STROBE
	CALL	DELAY		
	
	MOVLW	0x06		;ENTRY MODE SET
	CALL	STROBE
	CALL	DELAY

	MOVLW	0x01		;CLEAR DISPLAY
	CALL	STROBE
	CALL	MS2
	RETLW	0
;**********************************************************



;******* STROBE/DATS ******************
; SENDS DATA TO LCD DISPLAY MODULE (4 BIT MODE)   

STROBE	BCF	RA,RS		;SELECT COMMAND REGISTER
	GOTO	CM
DATS	BSF	RA,RS		;SELECT DATA REGISTER
CM	MOVWF	CHR		;STORE CHAR TO DISPLAY
	SWAPF	CHR,0           ;SWAP UPPER AND LOWER NIBBLES (4 BIT MODE)
	ANDLW	0x0F		;MASK OFF UPPER 4 BITS
	MOVWF	RB		;SEND DATA TO DISPLAY		
	BSF	RA,ENA		;ENA HIGH
	NOP			
	BCF	RA,ENA		;ENA LOW 

	MOVLW   0x42		;DELAY LOOP
        MOVWF   COUNT1     
DL3    	DECFSZ  COUNT1,1
        GOTO    DL3    

	MOVF	CHR,0		;GET CHAR AGAIN 
	ANDLW	0x0F		;MASK OFF UPPER 4 BITS
	MOVWF	RB		;SEND DATA TO DISPLAY	
	BSF	RA,ENA		;ENA HIGH
	NOP			
	BCF	RA,ENA		;ENA LOW

	MOVLW   0x42 		;DELAY LOOP
        MOVWF   COUNT1     
DL4    	DECFSZ  COUNT1,1
        GOTO    DL4      
	RETLW	0	
;********************************************************************






;************ MOVE TO START OF LINE 2 *****************
LINE2	MOVLW	0xC0		;ADDRESS FOR SECOND LINE OF DISPLAY
	CALL	STROBE
	CALL	DELAY
	RETLW	0
;******************************************************

              

;************ CLEAR DISPLAY ***************************

CLEAR	MOVLW	0x01		;COMMAND TO CLEAR DISPLAY
	CALL	STROBE
	CALL	MS2		;LONGER DELAY NEEDED WHEN CLEARING DISPLAY
	RETLW	0
;******************************************************	




;*********** MOVE TO HOME *****************************
HOME	MOVLW	0x02		;COMMAND TO HOME DISPLAY
	CALL	STROBE
	CALL	MS2
	RETLW	0
;******************************************************





	









;********* MAIN PROG ************
;INITIALISE PORTS


START
CMCON=7
	BSF	3,5		;SWITCH TO F REGISTER PAGE 1 	
	MOVLW	0x10
	MOVWF	RA		;RA 0 TO 3 OUTPUTS, RA 4 INPUT
	MOVLW	0xF0		;RB 4 TO 7 INPUTS			
	MOVWF	RB

	MOVLW	0xA7
	MOVWF	0X01		;PRESCALER /256, RB PULL UP DIS.
	BCF	3,5		;SWITCH TO F REGISTER PAGE 0	
	CLRF	RA
	CLRF	RB


	BSF	RA,HUFF		;HUFF LINE HIGH
	BCF	RA,PUFF		;PUFF LINE LOW
				;SETS OUTPUT AT ABOUT 2.5VDC

	BCF	FLAGS,LOK_FLG	;LOOP IS NOT LOCKED

	CALL	LCDINIT		;INITIALIZE LCD MODULE   
 

	MOVLW	'W'
	CALL	DATS 
	MOVLW	'6'
	CALL	DATS 
	MOVLW	'J'
	CALL	DATS
	MOVLW	'F'
	CALL	DATS
	MOVLW	'R'
	CALL	DATS
	MOVLW	' '
	CALL	DATS
	MOVLW	'H'
	CALL	DATS
	MOVLW	'B'
	CALL	DATS

	CALL	LINE2 

	MOVLW	'S'
	CALL	DATS
	MOVLW	'S'
	CALL	DATS
	MOVLW	'B'
	CALL	DATS

	MOVLW	' '
	CALL	DATS
	MOVLW	'X'
	CALL	DATS
	MOVLW	'C'
	CALL	DATS
	MOVLW	'V'
	CALL	DATS
	MOVLW	'R'
	CALL	DATS

	
	MOVLW	0x28		;Delay for 4 sec.	
	CALL	DECI
	CALL	CLEAR

	CALL	LINE2		;WRITE "Mhz" AT START OF LINE 2
	MOVLW	' '
	CALL	DATS
	MOVLW	'M'
	CALL	DATS
	MOVLW	'H'
	CALL	DATS
	MOVLW	'z'
	CALL	DATS
	MOVLW	' '
	CALL	DATS

	MOVLW	0x04
	MOVWF	UDC		;UPDATE DISPLAY EVERY 4 COUNTS

CNT_AGN	CLRF	RB		;CLOSE BOTH GATES, RESET LOW

	CLRF	M_BYTE		;RESET LOW AND MID BYTE COUNT REGISTERS
	CLRF	L_BYTE

	BSF	RB,RESET	;RESET EXTERNAL COUNTER (393)
	NOP
	BCF	RB,RESET
	
	CLRF	RTCC		;RESET INTERNAL COUNT (INCLUDING PRESCALER)

	BSF	RB,UP_CNT
	BSF	RB,GATE		;OPEN GATE'S
	CALL	MS100		;100MS DELAY 
	BCF	RB,GATE		;CLOSE GATE(COUNT COMPLETE)
	BCF	RB,UP_CNT

	MOVF	RTCC,W		;GET HIGH BYTE		
	MOVWF	H_BYTE		;STORE HIGH BYTE
	
	BSF	3,5		;SWITCH TO F REGISTER PAGE 1
	MOVLW	0x70
	MOVWF	RB		;MAKE RB,7 AN OUTPUT
	BCF	3,5		;SWITCH TO F REGISTER PAGE 0


	MOVF	H_BYTE,W
	MOVWF	TEMP
CLK_AGN	MOVF	TEMP,W
	XORWF	RTCC,W
	BTFSC	STATUS,Z
        GOTO	UP_1
	NOP	
	NOP
	BCF	STATUS,CARRY
	MOVLW	0xFF
	MOVWF	TEMP
	MOVF	M_BYTE,W
	SUBWF	TEMP,W
	MOVWF	M_BYTE
	GOTO	M_DONE



UP_1	BSF	RB,7		;CLOCK INTERNAL PRESCALER UP 1
	NOP
	BCF	RB,7
	INCF	M_BYTE,1
	GOTO	CLK_AGN


M_DONE	BSF	3,5		;SWITCH TO F REGISTER PAGE 1
	MOVLW	0xF0
	MOVWF	RB		;MAKE RB,7 AN INPUT AGAIN
	BCF	3,5		;SWITCH TO F REGISTER PAGE 0
NY	BTFSS	RB,7
	GOTO	UP_IT
CLK1	BTFSC	RB,7
	GOTO	UP_MOR
	NOP
	NOP
	BCF	STATUS,CARRY
	MOVLW	0xFF
	MOVWF	TEMP
	MOVF	L_BYTE,W
	SUBWF	TEMP,W
	MOVWF	L_BYTE
	INCF	L_BYTE,F		;!!!!!!!!!!!!!!
	BTFSC	STATUS,CARRY
	INCF	M_BYTE,F
	GOTO	CONVERT


UP_MOR	INCF	L_BYTE,1
	BSF	RB,UP_CNT
	NOP
	BCF	RB,UP_CNT
	GOTO	CLK1
	


UP_IT	INCF	L_BYTE,1
	BSF	RB,UP_CNT
	NOP
	BCF	RB,UP_CNT
	GOTO	NY  	

                                                 
;The IF addition/subtraction begins here. 



CONVERT	BTFSS	RB,UP_DWN	;TEST UP_DWN INPUT
	GOTO	SUB_IF

	BTFSC	RB,SBS		;TEST USB/LSB INPUT
	GOTO	ADD_HI

	MOVLW	0x0C		;Add IF 7.99850
	ADDWF	L_BYTE,F
	BTFSC	STATUS,CARRY	;0C346A HEX = 799850 Dec.
	INCF	M_BYTE,F
	MOVLW	0x34
	ADDWF	M_BYTE,F
	BTFSC	STATUS,CARRY
	INCF	H_BYTE,F
	MOVLW	0x6A
	ADDWF	H_BYTE,F
        GOTO	O_DONE	


ADD_HI	MOVLW	0x0C		;Add IF 8.00150
	ADDWF	L_BYTE,F
	BTFSC	STATUS,CARRY	;0C3596 HEX = 800150 Dec.
	INCF	M_BYTE,F
	MOVLW	0x35
	ADDWF	M_BYTE,F
	BTFSC	STATUS,CARRY
	INCF	H_BYTE,F
	MOVLW	0x96
	ADDWF	H_BYTE,F
        GOTO	O_DONE		

;The IF is subtracted by adding the compliment of the IF.

SUB_IF	BTFSC	RB,SBS		;TEST SIDEBAND SELECT SWITCH
	GOTO	SUB_HI	

	MOVLW	0xF3			;Subtract IF by adding -IF
	ADDWF	L_BYTE,F
	BTFSC	STATUS,CARRY		;-799850 Dec = F3CB96 HEX
	INCF	M_BYTE,F
	MOVLW	0xCB
	ADDWF	M_BYTE,F
	BTFSC	STATUS,CARRY
	INCF	H_BYTE,F
	MOVLW	0x96
	ADDWF	H_BYTE,F
	GOTO	O_DONE

SUB_HI	MOVLW	0xF3			;Subtract IF by adding -IF
	ADDWF	L_BYTE,F
	BTFSC	STATUS,CARRY		;-800150 Dec = F3CA6A HEX
	INCF	M_BYTE,F
	MOVLW	0xCA
	ADDWF	M_BYTE,F
	BTFSC	STATUS,CARRY
	INCF	H_BYTE,F
	MOVLW	0x6A
	ADDWF	H_BYTE,F




O_DONE	MOVF	L_BYTE,W	;STORE CURRENT COUNT
	MOVWF	CNT1_L
	MOVF	M_BYTE,W
	MOVWF	CNT1_M
	MOVF	H_BYTE,W
	MOVWF	CNT1_H


	
	



	BTFSS	FLAGS,LOK_FLG
	GOTO	LOK_TST
	
	BTFSS	RB,BUTTON	;IS LOCK/UNLOCK BUTTON PRESSED
	GOTO	UNLOCK		;YES, UNLOCK LOOP.


DUNIT	MOVF	L,W
	SUBWF	CNT1_L,F
	BTFSS	STATUS,CARRY
	DECF	CNT1_M,F

                     
	MOVF	M,W
	SUBWF	CNT1_M,F
	BTFSS	STATUS,CARRY
	DECF	CNT1_H,F

	MOVF	H,W
	SUBWF	CNT1_H,F 


	BTFSS	STATUS,CARRY
	GOTO	PULSE_H


	MOVLW	'<'
	MOVWF	TEMP
	BCF	RA,PUFF		;OUTPUT LOW PULSE TO INTEGRATOR
	MOVF	CNT1_L,W	;GET ERROR LEVEL
	MOVWF	ERR_LEV
	GOTO	PULSE_T





PULSE_H	MOVLW	'>'
	MOVWF	TEMP
	BSF	RA,HUFF		;OUTPUT HIGH PULSE TO INTEGRATOR 
	MOVF	CNT1_L,W	;GET ERROR LEVEL
	MOVWF	ERR_LEV		;REMEMBER ERR_LEV IS NOW A NEG. VALUE
	COMF	ERR_LEV,F	;NEG ERR_LEV
;	INCF	ERR_LEV,F
	GOTO	PULSE_T

LOK_TST	BTFSS	RB,BUTTON
	GOTO	SETUP
	GOTO	DONE


;******* SET UP LOOP LOCK FREQ AND LOCK FLAG **********
SETUP	BSF	FLAGS,LOK_FLG		;SET LOCKED FLAG

	MOVF	CNT1_L,W		;SAVE CURRENT COUNT TO BE -
	MOVWF	L                       ;COMPARED TO LATER COUNTS
	MOVF	CNT1_M,W
	MOVWF	M
	MOVF	CNT1_H,W
	MOVWF	H 
	CALL	MS100			;EXTRA DELAY FOR BUTTON DEBOUNCE
	BCF	RA,HUFF			;HUFF LOW , PUFF HIGH -
	BSF	RA,PUFF			;LET OUTPUT FLOAT

	GOTO	DUNIT			;SETUP COMPLETE
;********************************************************
             

;****** UNLOCK LOOP *******

UNLOCK	BCF	FLAGS,LOK_FLG		;CLEAR LOCK FLAG (3,6)
	BSF	RA,HUFF			;SET OUTPUT AT 2.5VDC
	BCF	RA,PUFF
	CALL	LINE2
	MOVLW	' '
	CALL	DATS
	MOVLW	'M'
	CALL	DATS
	MOVLW	'H'
	CALL	DATS
	MOVLW	'z'
	CALL	DATS
	MOVLW	' '
	CALL	DATS
	MOVLW	' '
	CALL	DATS
	MOVLW	' '
	CALL	DATS
	CALL	MS100			;EXTRA DELAY FOR BUTTON DEBOUNCE
	GOTO	DONE
;**************************

EXTRA	CALL	MS2
	DECFSZ	COUNT3,F
	GOTO	EXTRA
        GOTO	NO_MORE


PULSE_T	CALL	MS2		;DELAY FOR 2MS
	MOVF	ERR_LEV,W
	MOVWF	COUNT3
	INCF	COUNT3,F
	DECFSZ	COUNT3,F
	GOTO	EXTRA
NO_MORE	BCF	RA,HUFF
	BSF	RA,PUFF		;FLOAT OUTPUT AGAIN
	CALL	LINE2

	MOVLW	' '
	CALL	DATS
	MOVF	LST_DIG,W
	CALL	DATS
	MOVLW	' '
	CALL	DATS
	MOVLW	'E'
	CALL	DATS
	MOVLW	0x0A
	SUBWF	ERR_LEV,W
	BTFSS	STATUS,CARRY
	GOTO	EC
	MOVLW	0x09
	MOVWF	ERR_LEV
	

EC	MOVLW	0x30		;CONVERT ERROR LEVEL TO ASCII
	ADDWF	ERR_LEV,W
	CALL	DATS
	MOVLW	' '
	CALL	DATS
	MOVF	TEMP,W
	CALL	DATS 



	MOVF	ERR_LEV,F
	BTFSC	STATUS,Z	;IS THE ERROR LEVEL = 0 ?
	GOTO	FMW
	MOVLW	0x05
	MOVWF	COUNT5
	GOTO	DONE

FMW	DECFSZ	COUNT5,F
	GOTO	DONE
	INCF	COUNT5,F
	GOTO	CNT_AGN




	


DONE	DECFSZ	UDC,F
	GOTO	CNT_AGN		;DON'T UPDATE DISPLAY

	MOVLW	0x02
	MOVWF	UDC		;UPDATE DISPLAY EVERY 2 COUNTS

	

	CALL	B2_BCD		;CONVERT COUNT TO BCD          

	CALL	HOME		;HOME DISPLAY

	MOVLW	0x30
	MOVWF	TEMP		;AMOUNT TO ADD TO CONVERT TO ASCII

	MOVF	R3,0		;GET FIRST BCD DIGIT
	ANDLW	0x0F            ;MASK OFF OTHER PACKED BCD DIGIT
	BTFSS	STATUS,Z	;IS IT A '0' ?
	GOTO	NO_BLNK
	MOVLW	0x20		;YES PRINT A BLANK SPACE
	CALL	DATS
	GOTO	NXT_DIG

NO_BLNK	ADDWF	TEMP,W
	CALL	DATS

NXT_DIG	SWAPF	R2,0		;GET NEXT DIGIT
	ANDLW	0x0F		;MASK OFF OTHER PACKED BCD DIGIT
	ADDWF	TEMP,W
	CALL	DATS		;DISPLAY IT

	MOVLW	'.'
	CALL	DATS


	MOVF	R2,0		;GET OTHER BCD DIGIT
	ANDLW	0x0F		;MASK OFF OTHER PACKED BCD DIGIT
	ADDWF	TEMP,W
	CALL	DATS

	SWAPF	R1,0		;GET NEXT DIGIT
	ANDLW	0x0F		;MASK OFF OTHER PACKED BCD DIGIT
	ADDWF	TEMP,W
	CALL	DATS		;DISPLAY IT

	MOVF	R1,0		;GET OTHER BCD DIGIT
	ANDLW	0x0F
	ADDWF	TEMP,W
	CALL	DATS

	SWAPF	R0,0		;GET NEXT DIGIT
	ANDLW	0x0F		;MASK OFF OTHER PACKED BCD DIGIT
	ADDWF	TEMP,W
	CALL	DATS		;DISPLAY IT

	MOVF	R0,0		;GET OTHER BCD DIGIT
	ANDLW	0x0F
	ADDWF	TEMP,W
	MOVWF	LST_DIG
	


	CALL	HOME




	GOTO	CNT_AGN		;ALL DONE , START AGAIN	






        END








